// Helper for exporting to VCARD, VCALENDAR files
function ExportHelper(name, lang) {
  this.name  = name;
  this.lang  = lang;
  this.lines = ["BEGIN:"+name];
  return this;
}

ExportHelper.prototype = {
  ended: false,
  
  memo: function(object, name, value, escaped) {
    var escape  = this.escape;
    var isArray = this.isArray;
    var lines   = this.lines;
    var sort    = this.sort;
    var lang    = this.lang;
    
    return {
      object: object,
      name: name,
      lang: lang,
      value: value,
      modifiers: "",
      escaped: escaped || false,

      lines:   lines,
      escape:  escape,
      isArray: isArray,
      sort:    sort,
      
      add: function(name) {
        if (value != null) {
          if (!name) name = this.name;
          lines.push(name + this.modifiers + ":" + this.value);
        }
      },
      
      utf8: function(escape) {
        if (this.value != null) {
          if (!escaped && escape != false)
            this.value = this.escape(this.value);
          
          if (this.lang)
            this.modifier("LANGUAGE",this.lang);
          
          this.modifiers += ";CHARSET=UTF-8";
        }
        return this;
      },
      
      mailto: function() {
        if (this.value != null) {
          this.modifiers += ";MAILTO";
        }
        return this;
      },
      
      typed: function(order) {
        if (this.value != null) {
          var type = this.object.types;
          if (!type) this.object.type;
          if (type) {
            if (this.isArray(type))
              type = this.sort(type, order).join(',');
            this.modifier('TYPE', type);
          }
        }
        return this;
      },
      
      resource: function() {
        if (this.value != null) {
          if (this.value.match(/^data:image\/([A-z]+);base64,(.*)$/)) {
            this.modifiers += ";ENCODING=b;TYPE=" + RegExp.$1;
            this.value = RegExp.$2;
          } else
            this.modifier('VALUE', 'uri');
        }
        return this;
      },
      
      fmt: function(typeKey) {
        if (this.value != null) {
          if (this.object[typeKey])
            this.modifier('FMTTYPE', this.object[typeKey]);
        }
        return this;
      },
      
      modProp: function(key) {
        if (this.value != null && this.object != null) {
          if (this.object[key])
            this.modifier(key.toUpperCase(), this.object[key]);
        }
        return this;
      },
      
      modifier: function(key,value) {
        this.modifiers += ";" + key + "=" + value;
      }
    }
  },
  
  prop: function(object, prop, defaultVal) {
    var value = null;
    var escaped = false;
    
    if (object && object[prop])
      value = object[prop];
    else if (typeof(defaultVal) != 'undefined' && defaultVal != null)
      value = defaultVal;

    if (value && this.isArray(value)) {
        value = this.escape(object[prop]).join("");
        escaped = true;
    }
    var m = this.memo(object, prop.toUpperCase(), value, escaped);
    if (m.value && m.value.__lang)
      m.lang = m.value.__lang;
    return m;
  },
  
  dateProp: function(object, prop) {
    var m = this.prop(object, prop);
    if (object[prop + "_date"]
        && !m.value.match(/^\d{8}(T\d{6}Z?)?$/)) {
      
      if (m.value.match(/^\d{8}T\d{4}(\d{2})?[+-]\d{4}$/)
          || m.value.match(/^\d{8}T\d{4}Z$/))
        m.value = FormatBase.prettyUTCDate(object[prop + "_date"], "%Y%m%dT%H%M%SZ");
      else
        m.value = FormatBase.prettyUTCDate(object[prop + "_date"], "%Y%m%d");
    }
    return m;
  },
  
  objProp: function(object, prop, valueName) {
    var m = this.prop(object, prop);
    if (m.value) {
      m.object = m.value;
      m.value = m.value[valueName];
    }
    return m;
  },
  
  commaList: function(object, prop) {
    return this.memo(object, prop.toUpperCase(),
        (object && object[prop])? this.escape(object[prop]).join(',') : null, true);
  },
  
  compList: function() {
    var object = arguments[0];
    if (!object) return this.memo(null, null, null);
    var values = [];
    if (this.isArray(object)) {
      values = object;
    } else {
      for (var i=1; i<arguments.length; i++)
        values.push(object[arguments[i]]);
    }
    return this.memo(object, null, this.buildComponentStringFromArr(values), true);
  },
  
  array: function(object, prop, valueName) {
    var arr = (object && object[prop])? object[prop] : null;
    var memos = null;
    if (arr) {
      memos = [];
      for (var i=0; i<arr.length; i++) {
        var value = valueName? arr[i][valueName] : arr[i];
        memos.push(this.memo(arr[i], prop.toUpperCase(), value));
      }
    }
    
    return {
      memos: memos,

      applyToAll: function(meth, args) {
        if (this.memos != null) {
          for (var i=0; i<this.memos.length; i++) {
            if (meth.apply) {
              meth.apply(this.memos[i], args);
            } else {
              if (this.memos[i][meth])
                this.memos[i][meth].apply(this.memos[i], args);
              else
                alert("method not found: " + meth.constructor);
            }
          }
        }
        return this;
      },
      typed: function(order) {
        return this.applyToAll('typed', [order]);
      },
      mailto: function() {
        return this.applyToAll('mailto', []);
      },
      add: function(name) {
        return this.applyToAll('add', [name]);
      },
      modProp: function(key) {
        return this.applyToAll('modProp', [key]);
      }
    };
  },
  
  buildComponentStringFromArr: function(arr) {
    var components = [];
    for (var i=0; i<arr.length; i++){
      if (arr[i]) {
        if (this.isArray(arr[i])) {
          arr[i] = this.escape(arr[i]);
          components[i] = arr[i].join(',');
        } else {
          components[i] = this.escape(arr[i]);
        }
      } else {
        components[i] = "";
      }
    }
    return components.join(';');
  },
  
  escape: function(s) {
    if (this.isArray(s)) {
      var arr = s.slice();
      for (var i=0; i<arr.length; i++)
        arr[i] = this.escape(arr[i]);
      return arr;
    } else
      return s.replace(/([,;])/g, "\\$1");
  },
  
  isArray: function(o) {
    return o.constructor == Array
  },
  
  sort: function(arr, order) {
    if (!order) return arr;
    var arr2 = arr.slice();
    var r = order.slice();
    var i = 0;
    while (i < r.length) {
      var found = false;
      for (var j=0; j<arr2.length; j++) {
        if (r[i] == arr2[j]) {
          found = true;
          arr2.splice(j, 1);
          break;
        }
      }
      if (!found) {
        r.splice(i, 1);
      } else {
        i++;
      }
    }
    return r;
  },
  
  toString: function() {
    if (!this.ended) {
      this.memo(null, "END", this.name).add();
      this.ended = true;
    }
    return this.lines.join("\n");
  }
};
